
#include <stdio.h>
#include "BaseConvert.h"
#include "StringUtils.h"

// Other utils
// SQLSafeprintf

/** Convert given string of bytes to a base64 representation to ASCII
 * encoded transmission (usually). The base64 string must be freed by
 * the caller.
 * 
 * @param data
 * The buffer of binary data to be converted.
 * 
 * @param bytes
 * The number of bytes in the buffer to be converted.
 * 
 * @return
 * A new string of base64 encoded data, representing the given bytes.
 * This must be freed eventually by the caller using free. */
char *BaseConvert::convertBytesToBase64(const char *data, int bytes)
{
   int databuf_size = apr_base64_encode_len(bytes);
   char *buf64 = (char *)malloc(sizeof(char)*(databuf_size+1));
   int len = apr_base64_encode_binary(buf64, (const unsigned char *)data, bytes);
   if (len > (databuf_size+1))
      errprint("Warning! Base64 encoding produced oversized output (%d > %d).", len, databuf_size+1);
   return buf64;
}

/** Convert given string of bytes to a hexadecimal representation. The
 * hexadecimal string must be freed by the caller.
 * 
 * @param data
 * The buffer of binary data to be converted.
 * 
 * @param bytes
 * The number of bytes in the buffer that must be converted.
 * 
 * @return
 * A new string of hexadecimal data, representing the given bytes.
 * This must be freed eventually by the caller using free. */
char *BaseConvert::convertBytesToHexadecimal(const char *data, int bytes)
{
   int databuf_size = 2*bytes;
   char *bufhex = (char *)malloc(sizeof(char)*(databuf_size+1));
   bufhex[0] = '\0';
   for (int i = 0; i < bytes; i++)
   {
      char buffer[3];
      sprintf(buffer, "%02x", (unsigned char)data[i]);
      memcpy(&(bufhex[i*2]), buffer, sizeof(char)*2);
   }
   bufhex[bytes*2] = '\0';
   int len = strlen(bufhex);
   if (len > (databuf_size+1))
      errprint("Warning! Hexadecimal encoding produced oversized output (%d > %d).", len, databuf_size+1);
   return bufhex;
}

/** Converts a base64 string to binary data. The resulting buffer must
 * be eventualy freed by the caller.
 * 
 * @param string
 * The string containing the ASCII characters that make up the base64 
 * represetnation of the binary data.
 * 
 * @param[in,out] bytes
 * The number of bytes in the strin on input and the number of bytes
 * in the binary data on output.
 * 
 * @return
 * A buffer containing the binary data that should be freed by the caller
 * at some later date. */
char *BaseConvert::convertBase64ToBytes(const char *string, int *bytes)
{
   char *bufstr = (char *)malloc(sizeof(char)*(strlen(string)+1));
   strcpy(bufstr, string);
   int databuf_size = apr_base64_decode_len(bufstr);
   char *buf64 = (char *)malloc(sizeof(char)*(databuf_size+1));
   int len = apr_base64_decode_binary((unsigned char *)buf64, bufstr);
   if (len > (databuf_size+1))
      errprint("Warning! Base64 decoding produced oversized output (%d > %d).", len, databuf_size+1);
   free(bufstr);
   if (bytes) *bytes = len;
   return buf64;
}

/** Converts hexadecimal to binary data. The buffer of binary data should at
 * some later point be freed by the caller.
 * 
 * @param data
 * The hexadecimal string representing the data.
 * 
 * @param[in,out] bytes
 * The number of bytes in the hexadecimal string that represents the binary
 * data on input and on output this holds the number of bytes in the binary
 * buffer pointer to in the return value.
 * 
 * @return
 * The buffer of the binary data that has been translated from the
 * hexadecimal data. This should later be freed by the caller. */
char *BaseConvert::convertHexadecimalToBytes(const char *data, int *bytes)
{
   if (bytes == NULL) return NULL;
   int databuf_size = ((*bytes)/2);
   unsigned char *bufhex = (unsigned char *)malloc(sizeof(unsigned char)*(databuf_size));
   for (int i = 0; i < databuf_size; i++)
   {
      char buffer[3];
      memcpy(buffer, &(data[i*2]), sizeof(unsigned char)*2);
      buffer[2] = '\0';
      unsigned int tint;
      sscanf(buffer, "%02x", &tint);
      bufhex[i] = tint;
   }
   (*bytes) = databuf_size;
   return (char *)bufhex;
}
